/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package util;

import entities.*;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.PrintStream;
import java.util.*;

/**
 *
 * @author dragan
 */
public class QueryUtils {

    /*public static List<Query> createQueries(Domain domain, QueryConfiguration qc, int noOfQueries) {
    List<Query> queries = new ArrayList<Query>();
    for (int i = 0; i < noOfQueries; i++) {
    queries.add(createQuery(domain, qc));
    }
    return queries;
    }*/
    public static List<Query> createUniqueQueries(Domain domain, List<Query> oldQueries, QueryConfiguration qc, int noOfQueries, List<Table> dimRelations) {
        List<Query> queries = new ArrayList<Query>();
        int i = 0;
        while (i < noOfQueries) {
            Query q = createQuery(domain, qc, dimRelations);
            if (!queries.contains(q) && !oldQueries.contains(q)) {
                queries.add(q);
                i++;
            }
        }
        return queries;
    }

    public static List<Query> createUniqueQueries(Domain domain, List<Query> oldQueries, QueryConfiguration qc, int noOfQueries) {
        return createUniqueQueries(domain, oldQueries, qc, noOfQueries, domain.getViewGraph().getRoot().getFKRelations());
    }

    public static List<Query> createUniqueQueries(Domain domain, QueryConfiguration qc, int noOfQueries, List<Table> dimRelations) {
        List<Query> queries = new ArrayList<Query>();
        int i = 0;
        while (i < noOfQueries) {
            Query q = createQuery(domain, qc, dimRelations);
            if (!queries.contains(q)) {
                queries.add(q);
                i++;
            }
        }
        return queries;
    }

    public static List<Query> createUniqueQueries(Domain domain, QueryConfiguration qc, int noOfQueries) {
        return createUniqueQueries(domain, qc, noOfQueries, domain.getViewGraph().getRoot().getFKRelations());
    }
    /* Creates a random query
     * @param domain: the domain of the problem
     * @param percentageGroupBy: the percentage of groupBy atributes in the query from all the atributes in the domain
     * @param percentageWhere: the percentage of where atributes in the query from the groupBy atributes. Where atributes is subset of groupBy atributes.
     * @return: a random query form all the atributes in the domain
     */

    public static Query createQuery(Domain domain, QueryConfiguration qc, List<Table> rootDimensions) {
        double percentageGroupBy = qc.getPercentageGroupBy();
        double percentageWhere = qc.getPercentageWhere();
        double percentageConditionEqal = qc.getPercentageEquals();

        List<Atribute> groupBy = new ArrayList<Atribute>();
        double probability = percentageGroupBy / 100;
        for (Table dimRelation : rootDimensions) {
            for (Table table : dimRelation) {
                for (Atribute a : table.getDescriptiveAtributes()) {
                    if (Math.random() < probability) {
                        groupBy.add(a);
                    }
                }
            }
        }
        List<Condition> where = new ArrayList<Condition>();
        probability = percentageWhere / 100;
        for (Atribute a : groupBy) {
            if (Math.random() < probability) {
                if (Math.random() < percentageConditionEqal / 100) {
                    where.add(new Condition(a, Condition.Predicate.Equal));
                } else {
                    where.add(new Condition(a, Condition.Predicate.Range));
                }
            }
        }
        return new Query(domain, where, groupBy);
    }

    public static Query createQuery(Domain domain, QueryConfiguration qc) {
        return createQuery(domain, qc, domain.getViewGraph().getRoot().getFKRelations());
    }

    public static Query createRandomQuery(Domain domain) {
        return createQuery(domain, new QueryConfiguration(Math.random() * 100.0, Math.random() * 100.0, Math.random() * 100.0), domain.getViewGraph().getRoot().getFKRelations());
    }

    public static List<Query> loadQueries(String fileName, Domain domain) {
        try {
            return loadQueries(new FileReader(fileName), domain);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static List<Query> loadQueries(FileReader fileReader, Domain domain) {
        try {
            List<Query> queries = new ArrayList<Query>();
            BufferedReader input = new BufferedReader(fileReader);
            String text = "", str = null;
            while ((str = input.readLine()) != null) {
                text += str;
            }
            HashMap<String, Atribute> atributesNames = new HashMap<String, Atribute>();
            for (Atribute a : domain.getAllAtributes()) {
                atributesNames.put(a.getName(), a);
            }
            input.close();
            String[] queryClauses = text.split("QUERY:");
            List<String> queryClauses1 = new ArrayList<String>();
            for (int i = 1; i < queryClauses.length; i++) {
                queryClauses1.add(queryClauses[i]);
            }
            for (String queryClause : queryClauses1) {
                String[] groupByClauses = queryClause.split("GROUP BY:");
                List<Atribute> groupBy = new ArrayList<Atribute>();
                List<Condition> where = new ArrayList<Condition>();
                if (groupByClauses.length > 1 && groupByClauses[1].split("WHERE:").length > 0) {
                    String groupByAtributes = groupByClauses[1].split("WHERE:")[0];
                    for (String atrName : groupByAtributes.split("\t")) {
                        groupBy.add(atributesNames.get(atrName));
                    }
                    if (groupByClauses[1].split("WHERE:").length > 1) {
                        String whereAtributes = groupByClauses[1].split("WHERE:")[1];
                        for (String atrName : whereAtributes.split("\t")) {
                            if (atrName.contains("=")) {
                                where.add(new Condition(atributesNames.get(atrName.substring(0, atrName.length() - 1)), Condition.Predicate.Equal));
                            } else {
                                where.add(new Condition(atributesNames.get(atrName.substring(0, atrName.length() - 2)), Condition.Predicate.Range));
                            }
                        }
                    }
                }
                queries.add(new Query(domain, where, groupBy));
            }
            return queries;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void saveQueries(String fileName, List<Query> queries, QueryConfiguration qc) {
        try {
            PrintStream out = new PrintStream(new FileOutputStream(fileName));
            int i = 1;
            out.println("Number of Queries: " + queries.size());
            out.println("GroupBy percentage: " + qc.getPercentageGroupBy());
            out.println("Select percentage: " + qc.getPercentageWhere());
            out.println("Equal Conditions percentage: " + qc.getPercentageEquals());
            out.println();
            for (Query query : queries) {
                out.println("QUERY:" + i++);
                out.println("GROUP BY:");
                for (Atribute a : query.getGroupby()) {
                    out.print(a.getName() + "\t");
                }
                out.println();
                out.println("WHERE:");
                for (Condition c : query.getWhere()) {
                    if (c.getPredicate().equals(Condition.Predicate.Equal)) {
                        out.print(c.getAtribute() + "=\t");
                    } else if (c.getPredicate().equals(Condition.Predicate.Range)) {
                        out.print(c.getAtribute() + "<>\t");
                    }
                }
                out.println();
                out.println();
            }
            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}
